package hellfire.system.graphics;

import android.opengl.GLES20;
import android.util.Log;
import hellfire.system.engine.Main;
import hellfire.system.engine.Task;

public class GLGPUCanvas implements GLDrawable
{
	//frame buffer object
	private int[] fbo;
	
	//texture storage
	private int[] texture;
	
	//some readiness flags
	private boolean isInitialized = false;
	
	//the image that contains our texture
	private GLTextureImage image = null;
	
	//dims of the target texture
	private GLVec2 canvasDims;
	
	//position and size of the image to be rendered
	private GLVec2 pos, dim;
	
	//backup for the viewport
	private int[] viewPortBackup;
	
	public GLGPUCanvas(int width, int height, GLVec2 pos, GLVec2 dim)
	{
		this.pos = pos;
		this.dim = dim;
		this.canvasDims = new GLVec2(width, height);
		Main.UI.renderer.runTask(new CreateFBOTask(this, width, height));
		viewPortBackup = new int[4];
		
	}
	public GLGPUCanvas(GLVec2 canvasDims, GLVec2 pos, GLVec2 dim)
	{
		this.canvasDims = canvasDims;
		this.pos = pos;
		this.dim = dim;
		Main.UI.renderer.runTask(new CreateFBOTask(this, (int)canvasDims.x(), (int)canvasDims.y()));
	}
	
	public void startRenderTarget() 
	{
		if(!isInitialized) return;
		GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo[0]);
		
		viewPortBackup = new int[4];
		GLES20.glGetIntegerv(GLES20.GL_VIEWPORT, viewPortBackup, 0);  
		
		//set the viewport to be the size of the texture
		GLES20.glViewport(0,0, (int)canvasDims.x(), (int)canvasDims.y());
	}
	
	public boolean isFBOInitialized()
	{
		return isInitialized;
	}
	
	public void stopRenderTarget()
	{
		if(!isInitialized) return;
		GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
		//Log.d("R", "viewport: " + viewPortBackup[0]);
		GLES20.glViewport(viewPortBackup[0], viewPortBackup[1], viewPortBackup[2], viewPortBackup[3]);
	}
	
	private void initialize(int fbo, int tex)
	{
		this.fbo = new int[]{fbo};
		this.texture = new int[]{tex};
		this.isInitialized = true;
	}
	
	private static class CreateFBOTask extends Task
	{
		int width, height;
		public CreateFBOTask(GLGPUCanvas canvas, int width, int height) 
		{
			super(canvas);
			this.width = width;
			this.height = height;
		}

		@Override
		public void run() 
		{
			GLGPUCanvas c = (GLGPUCanvas) this.param;
			
			int[] fbo = new int[1];
			int[] tex = new int[1];
			
			GLES20.glGenFramebuffers(1, fbo, 0);
			
			GLES20.glGenTextures(1, tex, 0);
			GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex[0]);
			GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0,GLES20.GL_RGBA, this.width, this.height, 0,GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
			GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
			GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
			
			GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo[0]);
			GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, tex[0], 0);
			GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
			
			c.initialize(fbo[0], tex[0]);
		}
	}

	@Override
	/**
	 * Render the inner texture
	 */
	public void draw(float[] matrix) 
	{
		if(isInitialized)
		{
			if(image == null)
			{
				//GLVec2 newDim = new GLVec2(dim.x(), -dim.y());
				image = new GLTextureImage(texture[0], pos, dim);
			}
			//Log.d("R", "rendering texture");
			image.draw(matrix);
		}
	}
	
	public GLVec2 getPos() 
	{
		return pos;
	}
	
	public void setPos(GLVec2 pos) 
	{
		this.pos = pos;
	}

}
